package net.fdukedom.epicurus.service;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

import net.fdukedom.epicurus.core.ws.CoreWSMessageHandler;
import net.fdukedom.epicurus.domain.entity.Plugin;
import net.fdukedom.epicurus.domain.entity.User;
import net.fdukedom.epicurus.domain.util.DomainException;
import net.fdukedom.epicurus.domain.util.PluginHelper;
import net.fdukedom.epicurus.domain.util.UserHelper;
import net.fdukedom.epicurus.resource.ResourceDispatcher;
import net.fdukedom.epicurus.service.interaction.Request;
import net.fdukedom.epicurus.service.interaction.RequestReader;
import net.fdukedom.epicurus.service.interaction.ResponseWriter;
import net.fdukedom.epicurus.tools.logging.Logger;
import net.fdukedom.epicurus.tools.logging.WriterId;
import net.fdukedom.epicurus.webinit.AppEnvironment;
import net.fdukedom.epicurus.domain.util.HibernateUtil;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.rmi.RemoteException;

//import java.util.ResourceBundle;

/**
 * Epicurus web service implementation.
 * 
 * @author Alexander Kirakozov
 */
@WebService(name = "Epicurus")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class EpicurusServiceWrapper implements EpicurusWSInterface {
	/**
	 * Log call information
	 * 
	 * @param info
	 *            information message
	 */
	private void logInformation(String info) {
		Logger.getInstance(WriterId.WEBSERVICE).logInfo(info);
	}

	/**
	 * Log call information for corresponding user
	 * 
	 * @param email
	 *            email of user
	 * @param info
	 *            information message
	 */
	private void logInformation(String email, String info) {
		Logger.getInstance(WriterId.WEBSERVICE).logInfo(email + ": " + info);
	}

	/**
	 * Log error information
	 * 
	 * @param error
	 *            message
	 */
	private void logError(String error) {
		Logger.getInstance(WriterId.WEBSERVICE).logError(error);
	}

	/**
	 * Try to indentify user
	 * 
	 * @param email
	 *            user email
	 * @param password
	 *            user password
	 * @return
	 */
	private User identifyUser(String email, String password) {
		User user = UserHelper.getInstance().findByEmail(email);
		if (user != null) {
			if (user.getPassword().equals(User.hash(password))) {
				return user;
			} else {
				logInformation(email, "inncorrect password");
			}
		} else {
			logInformation(email, "user wasn't found");
		}

		return null;
	}

	@WebMethod
	public boolean connect(String email, String password)
			throws RemoteException {
		try {
			HibernateUtil.newSession();
			logInformation(email, "tries to connect");
			if (identifyUser(email, password) != null) {
				logInformation(email, "connected succesfully");
				return true;
			}

			logInformation(email, "connected failed");
		} finally {
			HibernateUtil.closeSession();
		}
		return false;
	}

	@WebMethod
	public String getUserName(String email, String password) {
		User user;

		try {
			HibernateUtil.newSession();
			logInformation(email, "tries to get nick name");
			user = identifyUser(email, password);
		} finally {
			HibernateUtil.closeSession();
		}

		if (user != null) {
			return user.getName();
		}

		return null;
	}

	@WebMethod
	public Short getUserSex(String email, String password) {
		User user;

		try {
			HibernateUtil.newSession();
			logInformation(email, "tries to get sex property");
			user = identifyUser(email, password);
		} finally {
			HibernateUtil.closeSession();
		}

		if (user != null) {
			return user.getSex();
		}

		return null;
	}

	@WebMethod
	public boolean updateProfile(String email, String password,
			String userName, Short sex) {
		User user;

		try {
			HibernateUtil.newSession();
			logInformation(email, "tries to update profile information");
			user = identifyUser(email, password);
			if (user != null) {
				user.setName(userName);
				user.setSex(sex);

				UserHelper.getInstance().saveUser(user);
				logInformation(email, "profile was updated succesfully");
				return true;
			}

		} finally {
			HibernateUtil.closeSession();
		}
		return false;
	}

	@WebMethod
	public String getPluginsInfo() {
		Document pluginsDom = new Document();
		Element rootElement = new Element("PluginSet");
		pluginsDom.setRootElement(rootElement);

		try {
			HibernateUtil.newSession();
			logInformation("Tries to get plugin info");
			File pluginFolder = AppEnvironment.getPluginFolder();
			logInformation(pluginFolder.getAbsolutePath());
			File[] descriptions = pluginFolder.listFiles(new FilenameFilter() {
				public boolean accept(File dir, String name) {
					return name.endsWith("-pd.xml");
				}
			});

			SAXBuilder builder = new SAXBuilder();
			if (descriptions != null) {
				for (File descriptionFile : descriptions) {
					try {
						Document pluginDom = builder.build(descriptionFile);

						rootElement.getChildren().add(
								pluginDom.getRootElement().clone());
					} catch (JDOMException e) {
						logError("Plug-ins xml building exception. Plug-in file: "
								+ descriptionFile.getName()
								+ ". Exception message: " + e.getMessage());
					} catch (IOException e) {
						logError("Plug-ins xml building exception. Plug-in file: "
								+ descriptionFile.getName()
								+ ". Exception message: " + e.getMessage());
					}
				}
			}
		} finally {
			HibernateUtil.closeSession();
		}

		XMLOutputter out = new XMLOutputter();
		return out.outputString(pluginsDom);
	}

	@WebMethod
	public String invoke(String xmlRequest) throws RemoteException {
		Plugin plugin = null;

		try {
			HibernateUtil.newSession();
			RequestReader request = new RequestReader(xmlRequest);
			
			plugin = ResourceDispatcher.getInstance().findPluginByName(
					request.getPluginName());
			if (plugin != null) {
				WSMessageHandlerInterface handler = PluginHelper.getInstance()
						.getWsEndpointPlugin(plugin);
				return handler.process(xmlRequest); 
			} else {
				String msg = "Couldn't find plugin " + request.getPluginName();
				logInformation(msg);
				ResponseWriter writer = new ResponseWriter();
				
				writer.setMessage(msg);
				writer.setStatus(false);
				
				return writer.toString();
			}
		} catch (DomainException e) {
			String msg = "Couldn't load handler for " + plugin.getName()
					+ " plugin.";
			logInformation(msg);
			ResponseWriter writer = new ResponseWriter();

			writer.setMessage(msg);
			writer.setStatus(false);
			
			return writer.toString();
		} finally {
			HibernateUtil.closeSession();
		}
	}
}